package com.minelx.datamicroscope.querylanguage.data.sql;

import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.minelx.datamicroscope.querylanguage.data.CollectingKey;
import com.minelx.datamicroscope.querylanguage.data.Condition;

import java.util.List;

import static com.minelx.datamicroscope.querylanguage.data.QueryBuilder.strip;
import static java.util.stream.Collectors.toList;

public class JoinAliasedTablesFulfil implements AliasedTablesFulfil {

	private final SQLSelectQueryBlock wholeQueryBlock;

	private final SQLJoinTableSource fromTable;

	public JoinAliasedTablesFulfil(SQLSelectQueryBlock wholeQueryBlock, SQLJoinTableSource fromTable) {
		this.wholeQueryBlock = wholeQueryBlock;
		this.fromTable = fromTable;
	}

	@Override
	public void fulfil(AliasedTablesBuilder aliasedTablesBuilder) {
		AliasedTablesFulfil.create(fromTable.getLeft(), wholeQueryBlock)
				.fulfil(aliasedTablesBuilder);
		fulfilRightTable(aliasedTablesBuilder);
	}

	private void fulfilRightTable(AliasedTablesBuilder aliasedTablesBuilder) {
		SQLBinaryOpExpr whereExpr = (SQLBinaryOpExpr) fromTable.getCondition();
		SQLExprTableSource fromTableSource = (SQLExprTableSource) fromTable.getRight();
		CollectingJoinPoint collectingJoinPoint = CollectingJoinPoint.create(
				ConditionProvider.list(whereExpr),
				aliasedTablesBuilder);

		// all conditions
		List<Condition> conditions = ConditionProvider.list(wholeQueryBlock.getWhere()).stream()
				.filter(conditionProvider -> conditionProvider.left().tableAlias().equals(fromTableSource.getAlias()))
				.map(ConditionProvider::toCondition)
				.collect(toList());

		CollectingKey tableKey = new CollectingKey(
				strip(fromTableSource.getTableName(), "`"),
				collectingJoinPoint.collectingOnKeyMapping(),
				conditions);
		aliasedTablesBuilder.markAliasedTable(
				fromTableSource.getAlias(),
				tableKey,
				joinTypeToDescription(fromTable.getJoinType()));
	}

	private static String joinTypeToDescription(SQLJoinTableSource.JoinType joinType) {
		if (joinType == SQLJoinTableSource.JoinType.LEFT_OUTER_JOIN) {
			return "left";
		} else if (joinType == SQLJoinTableSource.JoinType.RIGHT_OUTER_JOIN) {
			return "right";
		} else if (joinType == SQLJoinTableSource.JoinType.INNER_JOIN) {
			return "inner";
		} else {
			throw new UnsupportedOperationException("JoinFulfil.joinTypeToDescription is not supported.");
		}
	}
}
